
/** @type {*} */
const PENDING = 'pending';  //  等待
const FULFILLED = 'fulfilled';  //  成功
const REJECTED = 'rejected';  //  失败

/**
 * 封装对于返回 value 是普通值还是 promise 对象的统一处理方式
 *
 * @author Ryan
 * @date 2020-10-30
 * @param {*} value
 * @param {*} promise
 * @param {*} resolve
 * @param {*} reject
 */
function resolvePromise(value, promise, resolve, reject) {
  // 判断传入的 value 是否是自己
  if(value === promise) {
    return new TypeError('Chaining cycle detected for promise #<Promise>');
  }

  // 判断 value 是普通值还是 promise 对象
  if(value instanceof MyPromise) {
    value.then(resolve, reject);
  } else {
    resolve(value);
  }
}

/**
 *  手写实现 Promise 源码
 * @author Ryan
 * @date 2020-10-30
 * @class MyPromise
 */
class MyPromise {
  /**
   * Creates an instance of MyPromise.
   * 构造函数，接收对象实例化时传入的参数（这里该参数为一个函数，传递了 resolve 和 reject 两个函数参数）
   * @author Ryan
   * @date 2020-10-30
   * @param {*} execute
   * @memberof MyPromise
   */
  constructor(execute) {
    // 设置 Promise 状态参数, 初始化为 等待状态
    this.status = PENDING;

    // 设置成功时接收的值，初始化为 undefined
    this.value = undefined;
    // 设置失败时接收的失败原因，初始化为 undefined
    this.reason = undefined;

    // 成功回调函数存放数组
    this.onFulfilleds = [];
    // 失败回调函数存放数组
    this.onRejecteds = [];

    // 绑定 resolve、reject 方法，解决调用时 this 指向问题
    this.resolve = this.resolve.bind(this);
    this.reject = this.reject.bind(this);

    try {
      execute(this.resolve, this.reject);
    } catch (error) {
      this.reject(error);
    }
  }

  /**
   * 接收成功传值
   *
   * @author Ryan
   * @date 2020-10-30
   * @param {*} value
   * @returns {*}  
   * @memberof MyPromise
   */
  resolve(value) {
    // 判断当前状态是否为等待状态，如果不是则直接返回
    if(this.status !== PENDING) return;

    // 更改 promise 状态
    this.status = FULFILLED;

    // 保存成功时传入的值
    this.value = value;

    // 循环执行成功回调函数数组中的参数
    while (this.onFulfilleds.length) this.onFulfilleds.shift()();
  }

  /**
   * 接收失败原因
   *
   * @author Ryan
   * @date 2020-10-30
   * @param {*} reason
   * @returns {*}  
   * @memberof MyPromise
   */
  reject(reason) {
    // 判断当前状态是否为等待状态，如果不是则直接返回
    if(this.status !== PENDING) return;

    // 更改 promise 状态
    this.status = REJECTED;

    // 保存失败时传入的失败原因
    this.reason = reason;

    // 循环执行失败回调函数数组中的参数
    while (this.onRejecteds.length) this.onRejecteds.shift()();
  }

  /**
   * 接收成功回调、失败回调两个参数
   *
   * @author Ryan
   * @date 2020-10-30
   * @param {*} onFulfilled
   * @param {*} onRejected
   * @memberof MyPromise
   */
  then(onFulfilled, onRejected) {
    // then 方法可以不传回调函数，此时应该给下一个 then 传一个默认的回调函数
    onFulfilled = onFulfilled ? onFulfilled : value => value;
    onRejected = onRejected ? onRejected : reason => { throw reason };

    // 处理 then 的链式回调，所以 then 方法每次返回的是一个新的 Promise 对象
    let promise2 = new MyPromise((resolve, reject) => {
      if(this.status === FULFILLED) {
        // 使用 setTimeout 是为了解决 promise2 未定义错误
        setTimeout(() => {
          try {
            // 执行 then 方法的成功回调函数，并获取该函数 return 的值
            let v = onFulfilled(this.value);
            // 对该值进行判断并处理
            resolvePromise(v, promise2, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);
      } else if(this.status === REJECTED) {
        setTimeout(() => {
          try {
            // 执行 then 方法的失败回调函数，并获取该函数 return 的值
            let e = onRejected(this.reason);
            // 对该值进行判断并处理
            resolvePromise(e, promise2, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);
      } else {
        this.onFulfilleds.push(() => {
          setTimeout(() => {
            try {
              // 执行 then 方法的成功回调函数，并获取该函数 return 的值
              let v = onFulfilled(this.value);
              // 对该值进行判断并处理
              resolvePromise(v, promise2, resolve, reject);
            } catch (error) {
              reject(error);
            }
          }, 0);
        });

        this.onRejecteds.push(() => {
          setTimeout(() => {
            try {
              // 执行 then 方法的失败回调函数，并获取该函数 return 的值
              let e = onRejected(this.reason);
              // 对该值进行判断并处理
              resolvePromise(e, promise2, resolve, reject);
            } catch (error) {
              reject(error);
            }
          }, 0);
        });
      }
    });

    return promise2;
  }

  finally(callback) {
    // 调用 then 方法，可获取到当前 promise 状态
    return this.then(value => {
      // 使用 resolve 判断 callback() 是 promise 对象还是普通值，然后执行它，成功则返回值
      return MyPromise.resolve(callback()).then(() => value);
    }, reason => {
      // 失败则返回失败原因
      return MyPromise.resolve(callback()).then(() => { throw reason });
    });
  }

  catch(callback) {
    return this.then(undefined, callback);
  }

  /**
   * 静态方法 all，传入一个数组，并按顺序执行之后返回一个新的数组
   *
   * @author Ryan
   * @date 2020-10-30
   * @static
   * @param {*} array
   * @memberof MyPromise
   */
  static all(array) {
    // 返回结果数组
    let result = [];
    // 记录当前遍历次数
    let index = 0;

    return new MyPromise((resolve, reject) => {

      // 定义一个方法，操作 result 数组的新增
      function addData(key, value) {
        result[key] = value;
        index++;

        // 判断当操作到最后一次时，调用 resolve 回调函数，返回结果
        if(index === array.length) {
          resolve(result);
        }
      }

      for (let i = 0; i < array.length; i++) {
        const current = array[i];
        // 判断当前值是普通值还是 promise 对象
        if(current instanceof MyPromise) {
          // promise 对象
          current.then(value => addData(i, value), reason => reject(reason));
        } else {
          // 普通值
          addData(i, current);
        }
      }
    });
  }

  /**
   * 静态方法 resolve
   * 判断传入的 value 是普通值还是 promise 对象，如果是 promise 对象则原样返回
   * 如果是普通值，则 new 一个 Promise 对象并返回
   * @author Ryan
   * @date 2020-10-30
   * @static
   * @param {*} value
   * @returns {*}  
   * @memberof MyPromise
   */
  static resolve(value) {
    if(value instanceof MyPromise) return value;

    return new MyPromise((resolve, reject) => resolve(value));
  }
}

module.exports = MyPromise;